// -*- mode:c++ -*-

// Copyright (c) 2022 PLCT Lab
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


let {{
    def setDestWrapper(destRegId):
        return "setDestRegIdx(_numDestRegs++, " + destRegId + ");\n" + \
               "_numTypedDestRegs[VecRegClass]++;\n"
    def setSrcWrapper(srcRegId):
        return "setSrcRegIdx(_numSrcRegs++, " + srcRegId + ");\n"
    def setOldDestWrapper(destRegId):
        return """
        oldDstIdx = _numSrcRegs;
        setSrcRegIdx(_numSrcRegs++, %s);
        """ % destRegId
    def setSrcVL():
        return 'SET_VL_SRC();'
    def setSrcVm():
        return """
        SET_VM_SRC();
        """
    def vmDeclAndReadData():
        return '''
        VM_REQUIRED();
        '''
    def copyOldVd(vd_idx):
        return ''
    def loopWrapper(code, micro_inst = True):
        if micro_inst:
            upper_bound = "elem_num_per_vreg"
        else:
            upper_bound = "rVl"
        return '''
            for (uint32_t i = 0; i < %s; i++) {
                %s
            }
        ''' % (upper_bound, code)
    def maskCondWrapper(code, withvm = True):
        if withvm:
            return """
            if ((ei < rVl) && (this->vm || elem_mask(v0, ei))) {
                %s
            }
            """ % (code)
        else:
            return """
            if (ei < rVl) {
                %s
            }
            """ % (code)

    def eiDeclarePrefix(code, widening = False):
        if widening:
            return '''
            uint32_t ei = i + micro_vlmax * this->microIdx;
            ''' + code
        else:
            return '''
            uint32_t ei = i + elem_num_per_vreg * this->microIdx;
            ''' + code

    def wideningOpRegisterConstraintChecks(code):
        return code
        return '''
            const uint32_t num_microops = 1 << std::max<int64_t>(0, vtype_vlmul(machInst.vtype8) + 1);
            if ((machInst.vd % alignToPowerOfTwo(num_microops)) != 0) {
                std::string error =
                    csprintf("Unaligned Vd group in Widening op");
                return std::make_shared<IllegalInstFault>(error, machInst);
            }
            if ((machInst.vs2 <= machInst.vd) && (machInst.vd < (machInst.vs2 + num_microops - 1))) {
                // A destination vector register group can overlap a source vector
                // register group if The destination EEW is greater than the source
                // EEW, the source EMUL is at least 1, and the overlap is in the
                // highest- numbered part of the destination register group.
                std::string error =
                    csprintf("Unsupported overlap in Vs2 and Vd for Widening op");
                return std::make_shared<IllegalInstFault>(error, machInst);
            }
            ''' + code

    def narrowingOpRegisterConstraintChecks(code):
        return '''
            const uint32_t num_microops = 1 << std::max<int64_t>(0, vtype_vlmul(machInst.vtype8) + 1);
            if ((machInst.vs2 % alignToPowerOfTwo(num_microops)) != 0) {
                std::string error =
                    csprintf("Unaligned VS2 group in Narrowing op");
                return std::make_shared<IllegalInstFault>(error, machInst);
            }
            if ((machInst.vs2 < machInst.vd) && (machInst.vd <= (VS2 + num_microops - 1))) {
                // A destination vector register group can overlap a source vector
                // register group The destination EEW is smaller than the source EEW
                // and the overlap is in the lowest-numbered part of the source
                // register group
                std::string error =
                    csprintf("Unsupported overlap in Vs2 and Vd for Narrowing op");
                return std::make_shared<IllegalInstFault>(error, machInst);
            }
        ''' + code

    def fflags_wrapper(code):
        return '''
        RegVal FFLAGS = xc->readMiscReg(MISCREG_FFLAGS);
        std::feclearexcept(FE_ALL_EXCEPT);
        ''' + code + '''
        FFLAGS |= softfloat_exceptionFlags;
        if (softfloat_exceptionFlags) {
            softfloat_exceptionFlags = 0;
            xc->setMiscReg(MISCREG_FFLAGS, FFLAGS);
        }
        '''
}};


def format VectorIntFormat(code, category, *flags) {{
    macroop_class_name = 'VectorArithMacroInst'
    microop_class_name = 'VectorArithMicroInst'

    if name == "vid_v" :
        macroop_class_name = 'VectorVMUNARY0MacroInst'
        microp_class_name = 'VectorVMUNARY0MicroInst'

    iop = InstObjParams(name, Name, macroop_class_name, {'code': code},
                        flags)
    inst_name, inst_suffix = name.split("_", maxsplit=1)
    v0_required = inst_name not in ["vmv"]
    mask_cond = v0_required and (inst_suffix not in ['vvm', 'vxm', 'vim'])
    need_elem_idx = mask_cond or code.find("ei") != -1

    dest_reg_id = "RegId(VecRegClass, _machInst.vd + _microIdx)"

    num_src_regs = 0

    src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx)"
    num_src_regs += 1

    src1_reg_id = ""
    if category in ["OPIVV", "OPMVV"]:
        src1_reg_id = "RegId(VecRegClass, _machInst.vs1 + _microIdx)"
        num_src_regs += 1
    elif category in ["OPIVX", "OPMVX"]:
        src1_reg_id = "RegId(IntRegClass, _machInst.rs1)"
        num_src_regs += 1
    elif category == "OPIVI":
        pass
    else:
        error("not supported category for VectorIntFormat: %s" % category)

    old_vd_idx = num_src_regs

    set_dest_reg_idx = setDestWrapper(dest_reg_id)

    set_src_reg_idx = ""
    if category != "OPIVI":
        set_src_reg_idx += setSrcWrapper(src1_reg_id)
    set_src_reg_idx += setSrcWrapper(src2_reg_id)
    set_src_reg_idx += setOldDestWrapper(dest_reg_id)
    set_src_reg_idx += setSrcVL()
    if v0_required:
        set_src_reg_idx += setSrcVm()

    # code
    code = maskCondWrapper(code, mask_cond)
    code = eiDeclarePrefix(code)
    code = loopWrapper(code)

    vm_decl_rd = ""
    if v0_required:
        vm_decl_rd = vmDeclAndReadData()

    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        microop_class_name,
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'copy_old_vd': copyOldVd(old_vd_idx)},
        flags)

    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorIntMicroDeclare.subst(microiop) + \
        VectorIntMicroConstructor.subst(microiop) + \
        VectorIntMicroExecute.subst(microiop) + \
        VectorIntMacroDeclare.subst(iop) + \
        VectorIntMacroConstructor.subst(iop)

    decode_block = VectorIntDecodeBlock.subst(iop)
}};


def format VectorIntExtFormat(code, category, *flags) {{
    iop = InstObjParams(name, Name, 'VectorArithMacroInst', {'code': code},
                        flags)
    inst_name, inst_suffix = name.split("_", maxsplit=1)
    ext_div = int(inst_suffix[-1])

    old_vd_idx = 1
    dest_reg_id = "RegId(VecRegClass, _machInst.vd + _microIdx)"
    src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx / " + \
                      str(ext_div) + ")"
    src3_reg_id = "RegId(VecRegClass, _machInst.vs3 + _microIdx)"

    set_dest_reg_idx = setDestWrapper(dest_reg_id)

    set_src_reg_idx = ""
    set_src_reg_idx += setSrcWrapper(src2_reg_id)
    set_src_reg_idx += setOldDestWrapper(dest_reg_id)
    set_src_reg_idx += setSrcVL()
    set_src_reg_idx += setSrcVm()

    code = maskCondWrapper(code)
    code = eiDeclarePrefix(code)
    code = loopWrapper(code)
    vm_decl_rd = vmDeclAndReadData()

    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        'VectorArithMicroInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'copy_old_vd': copyOldVd(old_vd_idx),
         'ext_div': ext_div},
        flags)

    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorIntExtMicroDeclare.subst(microiop) + \
        VectorIntMicroConstructor.subst(microiop) + \
        VectorIntExtMicroExecute.subst(microiop) + \
        VectorIntExtMacroDeclare.subst(iop) + \
        VectorIntMacroConstructor.subst(iop)

    decode_block = VectorIntDecodeBlock.subst(iop)
}};

def format VectorIntWideningFormat(code, category, *flags) {{
    iop = InstObjParams(name, Name, 'VectorArithMacroInst', {'code': code},
                        flags)
    inst_name, inst_suffix = name.split("_", maxsplit=1)
    v0_required = True
    mask_cond = v0_required
    need_elem_idx = mask_cond or code.find("ei") != -1
    old_vd_idx = 2
    dest_reg_id = "RegId(VecRegClass, _machInst.vd + _microIdx)"
    src1_reg_id = ""
    if category in ["OPIVV", "OPMVV"]:
        src1_reg_id = "RegId(VecRegClass, _machInst.vs1 + _microIdx / 2)"
    elif category in ["OPIVX", "OPMVX"]:
        src1_reg_id = "RegId(IntRegClass, _machInst.rs1)"
    else:
        error("not supported category for VectorIntFormat: %s" % category)
    src2_reg_id = ""
    if inst_suffix in ["vv", "vx"]:
        src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx / 2)"
    elif inst_suffix in ["wv", "wx"]:
        src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx)"

    set_dest_reg_idx = setDestWrapper(dest_reg_id)

    set_src_reg_idx = ""
    set_src_reg_idx += setSrcWrapper(src1_reg_id)
    set_src_reg_idx += setSrcWrapper(src2_reg_id)
    set_src_reg_idx += setOldDestWrapper(dest_reg_id)
    set_src_reg_idx += setSrcVL()
    if v0_required:
        set_src_reg_idx += setSrcVm()

    # code
    code = maskCondWrapper(code, mask_cond)
    code = eiDeclarePrefix(code, widening=True)
    code = loopWrapper(code)

    code = wideningOpRegisterConstraintChecks(code)

    vm_decl_rd = ""
    if v0_required:
        vm_decl_rd = vmDeclAndReadData()

    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        'VectorArithMicroInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'copy_old_vd': copyOldVd(old_vd_idx)},
        flags)

    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorIntWideningMicroDeclare.subst(microiop) + \
        VectorIntWideningMicroConstructor.subst(microiop) + \
        VectorIntWideningMicroExecute.subst(microiop) + \
        VectorIntWideningMacroDeclare.subst(iop) + \
        VectorIntWideningMacroConstructor.subst(iop)

    decode_block = VectorIntWideningDecodeBlock.subst(iop)
}};

def format VectorIntNarrowingFormat(code, category, *flags) {{
    iop = InstObjParams(name, Name, 'VectorArithMacroInst', {'code': code},
                        flags)
    mask_cond = True
    need_elem_idx = True

    old_vd_idx = 2
    dest_reg_id = "RegId(VecRegClass, _machInst.vd + _microIdx / 2)"
    if category in ["OPIVV"]:
        src1_reg_id = "RegId(VecRegClass, _machInst.vs1 + _microIdx / 2)"
    elif category in ["OPIVX"]:
        src1_reg_id = "RegId(IntRegClass, _machInst.rs1)"
    elif category == "OPIVI":
        old_vd_idx = 1
    else:
        error("not supported category for VectorIntFormat: %s" % category)
    src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx)"
    old_dest_reg_id = "RegId(VecRegClass, _machInst.vs3 + _microIdx / 2)"

    set_dest_reg_idx = setDestWrapper(dest_reg_id)
    set_src_reg_idx = ""
    if category != "OPIVI":
        set_src_reg_idx += setSrcWrapper(src1_reg_id)
    set_src_reg_idx += setSrcWrapper(src2_reg_id)
    set_src_reg_idx += setOldDestWrapper(old_dest_reg_id)
    set_src_reg_idx += setSrcVL()
    set_src_reg_idx += setSrcVm()
    # code
    code = maskCondWrapper(code)
    code = eiDeclarePrefix(code, widening=True)
    code = loopWrapper(code)
    code = narrowingOpRegisterConstraintChecks(code)
    vm_decl_rd = vmDeclAndReadData()

    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        'VectorArithMicroInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'copy_old_vd': copyOldVd(old_vd_idx),
         },
        flags)

    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorIntWideningMicroDeclare.subst(microiop) + \
        VectorIntWideningMicroConstructor.subst(microiop) + \
        VectorIntNarrowingMicroExecute.subst(microiop) + \
        VectorIntWideningMacroDeclare.subst(iop) + \
        VectorIntWideningMacroConstructor.subst(iop)

    decode_block = VectorIntWideningDecodeBlock.subst(iop)
}};

def format VectorIntMaskFormat(code, category, *flags) {{
    iop = InstObjParams(name,
        Name,
        'VectorArithMacroInst',
        {'code': code},
        flags)
    inst_name, inst_suffix = name.split("_", maxsplit=1)
    v0_required = not (inst_name in ["vmadc", "vmsbc"] \
        and inst_suffix in ["vv", "vx", "vi"])
    mask_cond = inst_name not in ['vmadc', 'vmsbc']
    need_elem_idx = mask_cond or code.find("ei") != -1

    old_vd_idx = 2
    dest_reg_id = "RegId(VecRegClass, VecTempReg0 + _microIdx)"
    src1_reg_id = ""
    if category == "OPIVV":
        src1_reg_id = "RegId(VecRegClass, _machInst.vs1 + _microIdx)"
    elif category == "OPIVX":
        src1_reg_id = "RegId(IntRegClass, _machInst.rs1)"
    elif category == "OPIVI":
        old_vd_idx = 1
    else:
        error("not supported category for VectorIntFormat: %s" % category)
    src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx)"
    old_dest_reg_id = "RegId(VecRegClass, _machInst.vd)"
    set_dest_reg_idx = setDestWrapper(dest_reg_id)
    set_src_reg_idx = ""
    if category != "OPIVI":
        set_src_reg_idx += setSrcWrapper(src1_reg_id)
    set_src_reg_idx += setSrcWrapper(src2_reg_id)
    set_src_reg_idx += setSrcVL()
    set_src_reg_idx += setOldDestWrapper(old_dest_reg_id)
    if v0_required:
        set_src_reg_idx += setSrcVm()

    #code
    code = maskCondWrapper(code, mask_cond)
    code = eiDeclarePrefix(code)
    code = loopWrapper(code)

    vm_decl_rd = ""
    if v0_required:
        vm_decl_rd = vmDeclAndReadData()

    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        'VectorArithMicroInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'copy_old_vd': copyOldVd(old_vd_idx)},
        flags)

    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorIntMaskMicroDeclare.subst(microiop) + \
        VectorIntMaskMicroConstructor.subst(microiop) + \
        VectorIntMaskMicroExecute.subst(microiop) + \
        VectorIntMaskMacroDeclare.subst(iop) + \
        VectorIntMaskMacroConstructor.subst(iop)
    decode_block = VectorIntDecodeBlock.subst(iop)
}};

def format VectorGatherFormat(code, category, *flags) {{
    inst_name, inst_suffix = name.split("_", maxsplit=1)
    if inst_name == "vrgatherei16":
        idx_type = "uint16_t"
    else:
        idx_type = "elem_type"
    iop = InstObjParams(name, Name, 'VectorArithMacroInst',
        {'idx_type': idx_type,
         'code': code},
        flags)
    old_vd_idx = 2
    dest_reg_id = "RegId(VecRegClass, _machInst.vd + vd_idx)"
    src1_reg_id = ""
    if category in ["OPIVV"]:
        src1_reg_id = "RegId(VecRegClass, _machInst.vs1 + vs1_idx)"
    elif category in ["OPIVX"]:
        src1_reg_id = "RegId(IntRegClass, _machInst.rs1)"
    elif category == "OPIVI":
        old_vd_idx = 1
    else:
        error("not supported category for VectorIntFormat: %s" % category)
    src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + vs2_idx)"

    set_dest_reg_idx = setDestWrapper(dest_reg_id)

    set_src_reg_idx = ""
    if category != "OPIVI":
        set_src_reg_idx += setSrcWrapper(src1_reg_id)
    set_src_reg_idx += setSrcWrapper(src2_reg_id)
    set_src_reg_idx += setOldDestWrapper(dest_reg_id)
    set_src_reg_idx += setSrcVL()
    set_src_reg_idx += setSrcVm()

    # code

    vm_decl_rd = vmDeclAndReadData()

    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        'VectorArithMicroInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'copy_old_vd': copyOldVd(old_vd_idx),
         'idx_type': idx_type},
        flags)

    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorGatherMicroDeclare.subst(microiop) + \
        VectorGatherMicroConstructor.subst(microiop) + \
        VectorGatherMicroExecute.subst(microiop) + \
        VectorGatherMacroDeclare.subst(iop) + \
        VectorGatherMacroConstructor.subst(iop)

    decode_block = VectorGatherDecodeBlock.subst(iop)

}};

def format VectorFloatFormat(code, category, *flags) {{
    iop = InstObjParams(name, Name, 'VectorArithMacroInst', {'code': code},
                        flags)
    inst_name, inst_suffix = name.split("_", maxsplit=1)
    v0_required = inst_name not in ["vfmv"]
    mask_cond = v0_required and (inst_suffix not in ['vvm', 'vfm'])
    need_elem_idx = mask_cond or code.find("ei") != -1

    dest_reg_id = "RegId(VecRegClass, _machInst.vd + _microIdx)"
    src1_reg_id = ""
    if category == "OPFVV":
        src1_reg_id = "RegId(VecRegClass, _machInst.vs1 + _microIdx)"
    elif category == "OPFVF":
        src1_reg_id = "RegId(FloatRegClass, _machInst.rs1)"
    else:
        error("not supported category for VectorFloatFormat: %s" % category)
    src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx)"
    src3_reg_id = "RegId(VecRegClass, _machInst.vs3 + _microIdx)"

    set_dest_reg_idx = setDestWrapper(dest_reg_id)

    set_src_reg_idx = ""
    set_src_reg_idx += setSrcWrapper(src1_reg_id)
    set_src_reg_idx += setSrcWrapper(src2_reg_id)
    set_src_reg_idx += setSrcWrapper(src3_reg_id)
    set_src_reg_idx += setOldDestWrapper(dest_reg_id)
    set_src_reg_idx += setSrcVL()
    if v0_required:
        set_src_reg_idx += setSrcVm()
    # code
    code = maskCondWrapper(code, mask_cond)
    code = eiDeclarePrefix(code)
    code = loopWrapper(code)
    code = fflags_wrapper(code)

    vm_decl_rd = ""
    if v0_required:
        vm_decl_rd = vmDeclAndReadData()

    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        'VectorArithMicroInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'copy_old_vd': copyOldVd(2)},
        flags)

    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorFloatMicroDeclare.subst(microiop) + \
        VectorFloatMicroConstructor.subst(microiop) + \
        VectorFloatMicroExecute.subst(microiop) + \
        VectorFloatMacroDeclare.subst(iop) + \
        VectorFloatMacroConstructor.subst(iop)

    decode_block = VectorFloatDecodeBlock.subst(iop)
}};

def format VectorFloatCvtFormat(code, category, *flags) {{
    iop = InstObjParams(name, Name, 'VectorArithMacroInst', {'code': code},
                        flags)

    old_vd_idx = 1
    dest_reg_id = "RegId(VecRegClass, _machInst.vd + _microIdx)"
    src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx)"

    set_dest_reg_idx = setDestWrapper(dest_reg_id)

    set_src_reg_idx = ""
    set_src_reg_idx += setSrcWrapper(src2_reg_id)
    set_src_reg_idx += setOldDestWrapper(dest_reg_id)
    set_src_reg_idx += setSrcVL()
    set_src_reg_idx += setSrcVm()
    code = maskCondWrapper(code)
    code = eiDeclarePrefix(code)
    code = loopWrapper(code)
    code = fflags_wrapper(code)

    vm_decl_rd = vmDeclAndReadData()

    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        'VectorArithMicroInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'copy_old_vd': copyOldVd(old_vd_idx)},
        flags)

    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorFloatCvtMicroDeclare.subst(microiop) + \
        VectorFloatMicroConstructor.subst(microiop) + \
        VectorFloatMicroExecute.subst(microiop) + \
        VectorFloatCvtMacroDeclare.subst(iop) + \
        VectorFloatMacroConstructor.subst(iop)

    decode_block = VectorFloatDecodeBlock.subst(iop)
}};

def format VectorFloatWideningFormat(code, category, *flags) {{
    iop = InstObjParams(name, Name, 'VectorArithMacroInst', {'code': code},
                        flags)
    inst_name, inst_suffix = name.split("_", maxsplit=1)
    v0_required = True
    mask_cond = v0_required
    need_elem_idx = mask_cond or code.find("ei") != -1

    dest_reg_id = "RegId(VecRegClass, _machInst.vd + _microIdx)"
    src1_reg_id = ""
    if category in ["OPFVV"]:
        src1_reg_id = "RegId(VecRegClass, _machInst.vs1 + _microIdx / 2)"
    elif category in ["OPFVF"]:
        src1_reg_id = "RegId(FloatRegClass, _machInst.rs1)"
    else:
        error("not supported category for VectorFloatFormat: %s" % category)
    src2_reg_id = ""
    if inst_suffix in ["vv", "vf"]:
        src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx / 2)"
    elif inst_suffix in ["wv", "wf"]:
        src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx)"
    src3_reg_id = "RegId(VecRegClass, _machInst.vs3 + _microIdx)"

    set_dest_reg_idx = setDestWrapper(dest_reg_id)

    set_src_reg_idx = ""
    set_src_reg_idx += setSrcWrapper(src1_reg_id)
    set_src_reg_idx += setSrcWrapper(src2_reg_id)
    set_src_reg_idx += setSrcWrapper(src3_reg_id)
    set_src_reg_idx += setOldDestWrapper(dest_reg_id)
    set_src_reg_idx += setSrcVL()
    if v0_required:
        set_src_reg_idx += setSrcVm()

    # code
    code = maskCondWrapper(code, mask_cond)
    code = eiDeclarePrefix(code, widening=True)
    code = loopWrapper(code)
    code = fflags_wrapper(code)

    code = wideningOpRegisterConstraintChecks(code)

    vm_decl_rd = ""
    if v0_required:
        vm_decl_rd = vmDeclAndReadData()

    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        'VectorArithMicroInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'copy_old_vd': copyOldVd(2)},
        flags)

    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorIntWideningMicroDeclare.subst(microiop) + \
        VectorIntWideningMicroConstructor.subst(microiop) + \
        VectorFloatWideningMicroExecute.subst(microiop) + \
        VectorIntWideningMacroDeclare.subst(iop) + \
        VectorIntWideningMacroConstructor.subst(iop)

    decode_block = VectorFloatWideningDecodeBlock.subst(iop)
}};

def format VectorFloatWideningCvtFormat(code, category, *flags) {{
    iop = InstObjParams(name, Name, 'VectorArithMacroInst', {'code': code},
                        flags)

    old_vd_idx = 1
    dest_reg_id = "RegId(VecRegClass, _machInst.vd + _microIdx)"
    src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx / 2)"

    set_dest_reg_idx = setDestWrapper(dest_reg_id)

    set_src_reg_idx = ""
    set_src_reg_idx += setSrcWrapper(src2_reg_id)
    set_src_reg_idx += setOldDestWrapper(dest_reg_id)
    set_src_reg_idx += setSrcVL()
    set_src_reg_idx += setSrcVm()
    code = maskCondWrapper(code)
    code = eiDeclarePrefix(code, widening=True)
    code = loopWrapper(code)
    code = fflags_wrapper(code)

    vm_decl_rd = vmDeclAndReadData()

    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        'VectorArithMicroInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'copy_old_vd': copyOldVd(old_vd_idx)},
        flags)

    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorFloatCvtMicroDeclare.subst(microiop) + \
        VectorFloatMicroConstructor.subst(microiop) + \
        VectorFloatWideningMicroExecute.subst(microiop) + \
        VectorFloatCvtMacroDeclare.subst(iop) + \
        VectorIntWideningMacroConstructor.subst(iop)

    decode_block = VectorFloatWideningDecodeBlock.subst(iop)
}};

def format VectorFloatNarrowingCvtFormat(code, category, *flags) {{
    iop = InstObjParams(name, Name, 'VectorArithMacroInst', {'code': code},
                        flags)

    old_vd_idx = 1
    dest_reg_id = "RegId(VecRegClass, _machInst.vd + _microIdx / 2)"
    src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx)"

    set_dest_reg_idx = setDestWrapper(dest_reg_id)

    set_src_reg_idx = ""
    set_src_reg_idx += setSrcWrapper(src2_reg_id)
    set_src_reg_idx += setOldDestWrapper(dest_reg_id)
    set_src_reg_idx += setSrcVL()
    set_src_reg_idx += setSrcVm()
    code = maskCondWrapper(code)
    code = eiDeclarePrefix(code, widening=True)
    code = loopWrapper(code)
    code = fflags_wrapper(code)
    code = narrowingOpRegisterConstraintChecks(code)

    vm_decl_rd = vmDeclAndReadData()

    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        'VectorArithMicroInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'copy_old_vd': copyOldVd(old_vd_idx)},
        flags)

    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorFloatCvtMicroDeclare.subst(microiop) + \
        VectorFloatMicroConstructor.subst(microiop) + \
        VectorFloatNarrowingMicroExecute.subst(microiop) + \
        VectorFloatCvtMacroDeclare.subst(iop) + \
        VectorIntWideningMacroConstructor.subst(iop)

    decode_block = VectorFloatWideningDecodeBlock.subst(iop)
}};

def format VectorFloatMaskFormat(code, category, *flags) {{
    iop = InstObjParams(name,
        Name,
        'VectorArithMacroInst',
        {'code': code},
        flags)
    dest_reg_id = "RegId(VecRegClass, VecTempReg0 + _microIdx)"
    src1_reg_id = ""
    if category == "OPFVV":
        src1_reg_id = "RegId(VecRegClass, _machInst.vs1 + _microIdx)"
    elif category == "OPFVF":
        src1_reg_id = "RegId(FloatRegClass, _machInst.rs1)"
    else:
        error("not supported category for VectorFloatFormat: %s" % category)
    src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx)"
    old_dest_reg_id = "RegId(VecRegClass, _machInst.vd)"
    set_dest_reg_idx = setDestWrapper(dest_reg_id)
    set_src_reg_idx = ""
    set_src_reg_idx += setSrcWrapper(src1_reg_id)
    set_src_reg_idx += setSrcWrapper(src2_reg_id)
    set_src_reg_idx += setOldDestWrapper(old_dest_reg_id)
    set_src_reg_idx += setSrcVL()
    set_src_reg_idx += setSrcVm()
    vm_decl_rd = vmDeclAndReadData()

    code = maskCondWrapper(code)
    code = eiDeclarePrefix(code)
    code = loopWrapper(code)
    code = fflags_wrapper(code)

    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        'VectorArithMicroInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'copy_old_vd': copyOldVd(2)},
        flags)

    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorFloatMaskMicroDeclare.subst(microiop) + \
        VectorFloatMaskMicroConstructor.subst(microiop) + \
        VectorFloatMaskMicroExecute.subst(microiop) + \
        VectorFloatMaskMacroDeclare.subst(iop) + \
        VectorFloatMaskMacroConstructor.subst(iop)
    decode_block = VectorFloatDecodeBlock.subst(iop)
}};

def format VMvWholeFormat(code, category, *flags) {{
    iop = InstObjParams(name, Name, 'VMvWholeMacroInst', {'code': code}, flags)

    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        'VMvWholeMicroInst',
        {'code': code},
        flags)

    header_output = \
        VMvWholeMacroDeclare.subst(iop) + \
        VMvWholeMicroDeclare.subst(microiop)
    decoder_output = \
        VMvWholeMacroConstructor.subst(iop) + \
        VMvWholeMicroConstructor.subst(microiop)
    exec_output = VMvWholeMicroExecute.subst(microiop)
    decode_block = BasicDecode.subst(iop)
}};

def format ViotaFormat(code, category, *flags){{
    iop = InstObjParams(name, Name, 'VectorArithMacroInst', {'code': code},
                        flags)

    inst_name, inst_suffix = name.split("_", maxsplit=1)
    dest_reg_id = "RegId(VecRegClass, _machInst.vd + _microIdx)"
    src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx)"
    # The tail of vector mask inst should be treated as tail-agnostic.
    # We treat it with tail-undisturbed policy, since
    # the test suits only support undisturbed policy.
    old_dest_reg_id = "RegId(VecRegClass, _machInst.vd + _microIdx)"

    set_src_reg_idx = ""
    set_src_reg_idx += setSrcWrapper(src2_reg_id)
    set_src_reg_idx += setOldDestWrapper(old_dest_reg_id)
    set_src_reg_idx += setSrcVL()

    set_dest_reg_idx = setDestWrapper(dest_reg_id)
    vm_decl_rd = vmDeclAndReadData()
    set_vm_idx = setSrcVm()

    microiop = InstObjParams(name+"_micro",
        Name+"Micro",
        'VectorArithMicroInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'set_vm_idx': set_vm_idx},
        flags)
    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        ViotaMicroDeclare.subst(microiop) + \
        ViotaMicroConstructor.subst(microiop) + \
        ViotaMicroExecute.subst(microiop)+\
        ViotaMacroDeclare.subst(iop) + \
        ViotaMacroConstructor.subst(iop)

    decode_block = VectorIntDecodeBlock.subst(iop)

}};

def format Vector1Vs1VdMaskFormat(code, category, *flags){{
    inst_name, inst_suffix = name.split("_", maxsplit=1)
    dest_reg_id = "RegId(VecRegClass, _machInst.vd)"
    src2_reg_id = "RegId(VecRegClass, _machInst.vs2)"
    # The tail of vector mask inst should be treated as tail-agnostic.
    # We treat it with tail-undisturbed policy, since
    # the test suits only support undisturbed policy.
    old_dest_reg_id = "RegId(VecRegClass, _machInst.vd)"
    set_src_reg_idx = ""
    set_src_reg_idx += setSrcWrapper(src2_reg_id)
    set_src_reg_idx += setOldDestWrapper(old_dest_reg_id)
    set_src_reg_idx += setSrcVL()

    set_dest_reg_idx = setDestWrapper(dest_reg_id)
    vm_decl_rd = vmDeclAndReadData()
    set_vm_idx = setSrcVm()
    iop = InstObjParams(name,
        Name,
        'VectorNonSplitInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'set_vm_idx': set_vm_idx,
         'copy_old_vd': copyOldVd(1)},
        flags)
    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        Vector1Vs1RdMaskDeclare.subst(iop) + \
        Vector1Vs1VdMaskConstructor.subst(iop) + \
        Vector1Vs1VdMaskExecute.subst(iop)

    decode_block = VectorMaskDecodeBlock.subst(iop)
}};

def format Vector1Vs1RdMaskFormat(code, category, *flags){{
    inst_name, inst_suffix = name.split("_", maxsplit=1)
    vm_decl_rd = vmDeclAndReadData()
    set_vm_idx = setSrcVm()
    iop = InstObjParams(name,
        Name,
        'VectorNonSplitInst',
        {'code': code,
         'vm_decl_rd': vm_decl_rd,
         'set_vm_idx': set_vm_idx},
        flags)
    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        Vector1Vs1RdMaskDeclare.subst(iop) + \
        Vector1Vs1RdMaskConstructor.subst(iop) + \
        Vector1Vs1RdMaskExecute.subst(iop)

    decode_block = VectorMaskDecodeBlock.subst(iop)
}};

def format VectorNonSplitFormat(code, category, *flags) {{
    inst_name, inst_suffix = name.split("_", maxsplit=1)
    vm_decl_rd = ""

    set_vm_idx = ""

    if inst_name == "vfmv" :
        code = fflags_wrapper(code)

    iop = InstObjParams(name,
        Name,
        'VectorNonSplitInst',
        {'code': code,
         'vm_decl_rd': vm_decl_rd,
         'set_vm_idx': set_vm_idx},
        flags)


    if inst_name == "vfmv" :
        execute_block = VectorFloatNonSplitExecute.subst(iop)
        decode_block = VectorFloatDecodeBlock.subst(iop)
    elif inst_name == "vmv" :
        execute_block = VectorIntNonSplitExecute.subst(iop)
        decode_block = VectorIntDecodeBlock.subst(iop)
    else :
        error("Unsupported inst for VectorNonSplitFormat: %s" % inst_name)

    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorNonSplitDeclare.subst(iop) + \
        VectorNonSplitConstructor.subst(iop) + \
        execute_block

}};

def format VectorMaskFormat(code, category, *flags) {{
    inst_name, inst_suffix = name.split("_", maxsplit=1)
    old_vd_idx = 2
    if category not in ["OPMVV"]:
        error("not supported category for VectorIntFormat: %s" % category)
    dest_reg_id = "RegId(VecRegClass, _machInst.vd)"
    src1_reg_id = "RegId(VecRegClass, _machInst.vs1)"
    src2_reg_id = "RegId(VecRegClass, _machInst.vs2)"

    # The tail of vector mask inst should be treated as tail-agnostic.
    # We treat it with tail-undisturbed policy, since
    # the test suits only support undisturbed policy.
    # TODO: remove it

    set_src_reg_idx = ""
    set_src_reg_idx += setSrcWrapper(src1_reg_id)
    set_src_reg_idx += setSrcWrapper(src2_reg_id)
    set_src_reg_idx += setOldDestWrapper(dest_reg_id)
    set_src_reg_idx += setSrcVL()

    set_dest_reg_idx = setDestWrapper(dest_reg_id)

    code = loopWrapper(code, micro_inst = False)

    iop = InstObjParams(name,
        Name,
        'VectorNonSplitInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'copy_old_vd': copyOldVd(old_vd_idx)},
        flags)
    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorMaskDeclare.subst(iop) + \
        VectorMaskConstructor.subst(iop) + \
        VectorMaskExecute.subst(iop)

    decode_block = VectorMaskDecodeBlock.subst(iop)
}};

def format VectorReduceIntFormat(code, category, *flags) {{
    iop = InstObjParams(name, Name, 'VectorArithMacroInst', {'code': code},
                        flags)
    inst_name, inst_suffix = name.split("_", maxsplit=1)
    dest_reg_id = "RegId(VecRegClass, _machInst.vd)"
    src1_reg_id = "RegId(VecRegClass, _machInst.vs1)"
    src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx)"
    old_dest_reg_id = "RegId(VecRegClass, _machInst.vd)"

    set_dest_reg_idx = "if (pos == LastUop) {" + setDestWrapper(dest_reg_id) + "}\n"
    set_dest_reg_idx += "else {" + setDestWrapper("RegId(VecRegClass, VecTempReg0)") + "}\n"

    set_src_reg_idx = ""
    set_src_reg_idx += "if (pos == LastUop) {" + setOldDestWrapper(old_dest_reg_id) + "}\n"
    set_src_reg_idx += "if (pos != FirstUop) {" + setSrcWrapper("RegId(VecRegClass, VecTempReg0)") + "}\n"
    set_src_reg_idx += "if (pos != LastUop) {" + setSrcWrapper(src2_reg_id) + "}\n"
    set_src_reg_idx += "if (pos == LastUop) {" + setSrcWrapper(src1_reg_id) + "}\n"

    set_src_reg_idx += setSrcVL()
    set_src_reg_idx += setSrcVm()
    vm_decl_rd = vmDeclAndReadData()

    if name.endswith('u_vs') :
        type_def = '''
            using vui [[maybe_unused]] = std::make_unsigned_t<ElemType>;
        '''
    else:
        type_def = '''
            using vui [[maybe_unused]] = std::make_signed_t<ElemType>;
        '''

    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        'VectorArithMicroInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'type_def': type_def,
         'copy_old_vd': copyOldVd(2)},
        flags)

    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorReduceMicroDeclare.subst(microiop) + \
        VectorReduceMicroConstructor.subst(microiop) + \
        VectorReduceIntMicroExecute.subst(microiop) + \
        VectorReduceMacroDeclare.subst(iop) + \
        VectorReduceMacroConstructor.subst(iop)
    decode_block = VectorIntDecodeBlock.subst(iop)
}};

def format VectorReduceFloatFormat(code, category, *flags) {{
    iop = InstObjParams(name, Name, 'VectorArithMacroInst', {'code': code},
                        flags)
    inst_name, inst_suffix = name.split("_", maxsplit=1)

    dest_reg_id = "RegId(VecRegClass, _machInst.vd)"
    src1_reg_id = "RegId(VecRegClass, _machInst.vs1)"
    src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx)"
    old_dest_reg_id = "RegId(VecRegClass, _machInst.vd)"

    set_dest_reg_idx = setDestWrapper(dest_reg_id)

    set_src_reg_idx = ""
    set_src_reg_idx += "if (pos == LastUop) {" + setOldDestWrapper(old_dest_reg_id) + "}"
    set_src_reg_idx += "if (pos != FirstUop) {" + setSrcWrapper("RegId(VecRegClass, VecTempReg0)") + "}"
    set_src_reg_idx += "if (pos != LastUop) {" + setSrcWrapper(src2_reg_id) + "}"
    set_src_reg_idx += "if (pos == LastUop) {" + setSrcWrapper(src1_reg_id) + "}"

    set_src_reg_idx += setSrcVL()
    set_src_reg_idx += setSrcVm()
    vm_decl_rd = vmDeclAndReadData()
    type_def = '''
        using et = ElemType;
        using vu = decltype(et::v);
    '''

    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        'VectorArithMicroInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'type_def': type_def,
         'copy_old_vd': copyOldVd(2)},
        flags)

    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorReduceMicroDeclare.subst(microiop) + \
        VectorReduceMicroConstructor.subst(microiop) + \
        VectorReduceFloatMicroExecute.subst(microiop) + \
        VectorReduceMacroDeclare.subst(iop) + \
        VectorReduceMacroConstructor.subst(iop)
    decode_block = VectorFloatDecodeBlock.subst(iop)
}};

def format VectorReduceIntWideningFormat(code, category, *flags) {{
    iop = InstObjParams(name, Name, 'VectorArithMacroInst', {'code': code},
                        flags)
    inst_name, inst_suffix = name.split("_", maxsplit=1)
    dest_reg_id = "RegId(VecRegClass, _machInst.vd)"
    src1_reg_id = "RegId(VecRegClass, _machInst.vs1)"
    src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx)"
    old_dest_reg_id = "RegId(VecRegClass, _machInst.vd)"
    set_dest_reg_idx = setDestWrapper(dest_reg_id)

    set_src_reg_idx = ""
    set_src_reg_idx += "if (pos == LastUop) {" + setOldDestWrapper(old_dest_reg_id) + "}"
    set_src_reg_idx += "if (pos != FirstUop) {" + setSrcWrapper("RegId(VecRegClass, VecTempReg0)") + "}"
    set_src_reg_idx += "if (pos != LastUop) {" + setSrcWrapper(src2_reg_id) + "}"
    set_src_reg_idx += "if (pos == LastUop) {" + setSrcWrapper(src1_reg_id) + "}"

    set_src_reg_idx += setSrcVL()
    set_src_reg_idx += setSrcVm()
    vm_decl_rd = vmDeclAndReadData()

    if name.endswith('u_vs') :
        type_def = """
        using vui [[maybe_unused]] = std::make_unsigned_t<ElemType>;
        using vwui [[maybe_unused]] = typename double_width<vui>::type;
        """
    else :
        type_def = """
        using vui [[maybe_unused]] = std::make_signed_t<ElemType>;
        using vwui [[maybe_unused]] = typename double_width<vui>::type;
        """

    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        'VectorArithMicroInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'type_def': type_def,
         'copy_old_vd': copyOldVd(2)},
        flags)

    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorReduceMicroDeclare.subst(microiop) + \
        VectorReduceMicroConstructor.subst(microiop) + \
        VectorReduceIntWideningMicroExecute.subst(microiop) + \
        VectorReduceMacroDeclare.subst(iop) + \
        VectorReduceMacroConstructor.subst(iop)
    decode_block = VectorIntWideningDecodeBlock.subst(iop)
}};

def format VectorReduceFloatWideningFormat(code, category, *flags) {{
    iop = InstObjParams(name, Name, 'VectorArithMacroInst', {'code': code},
                        flags)
    inst_name, inst_suffix = name.split("_", maxsplit=1)
    dest_reg_id = "RegId(VecRegClass, _machInst.vd)"
    src1_reg_id = "RegId(VecRegClass, _machInst.vs1)"
    src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx)"
    old_dest_reg_id = "RegId(VecRegClass, _machInst.vd)"
    set_dest_reg_idx = setDestWrapper(dest_reg_id)

    set_src_reg_idx = ""
    set_src_reg_idx += "if (pos == LastUop) {" + setOldDestWrapper(old_dest_reg_id) + "}"
    set_src_reg_idx += "if (pos != FirstUop) {" + setSrcWrapper("RegId(VecRegClass, VecTempReg0)") + "}"
    set_src_reg_idx += "if (pos != LastUop) {" + setSrcWrapper(src2_reg_id) + "}"
    set_src_reg_idx += "if (pos == LastUop) {" + setSrcWrapper(src1_reg_id) + "}"

    set_src_reg_idx += setSrcVL()
    set_src_reg_idx += setSrcVm()
    vm_decl_rd = vmDeclAndReadData()


    type_def = '''
        using et = ElemType;
        using vu [[maybe_unused]] = decltype(et::v);
        using ewt = typename double_width<et>::type;
        using vwu = decltype(ewt::v);
    '''
    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        'VectorArithMicroInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'type_def': type_def,
         'copy_old_vd': copyOldVd(2)},
        flags)

    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorReduceMicroDeclare.subst(microiop) + \
        VectorReduceMicroConstructor.subst(microiop) + \
        VectorReduceFloatWideningMicroExecute.subst(microiop) + \
        VectorReduceMacroDeclare.subst(iop) + \
        VectorReduceMacroConstructor.subst(iop)
    decode_block = VectorFloatWideningDecodeBlock.subst(iop)
}};

def format VectorIntVxsatFormat(code, category, *flags) {{
    iop = InstObjParams(name, Name, 'VectorArithMacroInst', {'code': code},
                        flags)
    inst_name, inst_suffix = name.split("_", maxsplit=1)
    old_vd_idx = 2
    dest_reg_id = "RegId(VecRegClass, _machInst.vd + _microIdx)"
    src1_reg_id = ""
    if category in ["OPIVV"]:
        src1_reg_id = "RegId(VecRegClass, _machInst.vs1 + _microIdx)"
    elif category in ["OPIVX"]:
        src1_reg_id = "RegId(IntRegClass, _machInst.rs1)"
    elif category == "OPIVI":
        old_vd_idx = 1
    else:
        error("not supported category for VectorIntVxsatFormat: %s" % category)
    src2_reg_id = "RegId(VecRegClass, _machInst.vs2 + _microIdx)"
    src3_reg_id = "RegId(VecRegClass, _machInst.vs3 + _microIdx)"
    set_dest_reg_idx = setDestWrapper(dest_reg_id)

    set_src_reg_idx = ""
    if category != "OPIVI":
        set_src_reg_idx += setSrcWrapper(src1_reg_id)
    set_src_reg_idx += setSrcWrapper(src2_reg_id)
    set_src_reg_idx += setSrcWrapper(src3_reg_id)
    set_src_reg_idx += setOldDestWrapper(dest_reg_id)
    set_src_reg_idx += setSrcVL()
    set_src_reg_idx += setSrcVm()
    vm_decl_rd = vmDeclAndReadData()

    code = maskCondWrapper(code)
    code = eiDeclarePrefix(code)
    code = loopWrapper(code)

    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        'VectorArithMicroInst',
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'copy_old_vd': copyOldVd(old_vd_idx)},
        flags)

    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorIntVxsatMicroDeclare.subst(microiop) + \
        VectorIntVxsatMicroConstructor.subst(microiop) + \
        VectorIntMicroExecute.subst(microiop) + \
        VectorIntVxsatMacroDeclare.subst(iop) + \
        VectorIntVxsatMacroConstructor.subst(iop)

    decode_block = VectorIntDecodeBlock.subst(iop)
}};

let {{

def VectorSlideBase(name, Name, category, code, flags, macro_construtor,
        decode_template, micro_execute_template):
    macroop_class_name = 'VectorSlideMacroInst'
    microop_class_name = 'VectorSlideMicroInst'
    # Make sure flags are in lists (convert to lists if not).
    flags = makeList(flags)
    iop = InstObjParams(name, Name, macroop_class_name, {'code': code},
                        flags)
    inst_name, inst_suffix = name.split("_", maxsplit=1)
    dest_reg_id = "RegId(VecRegClass, vmi.microVd)"
    src2_reg_id = "RegId(VecRegClass, vmi.microVs2)"
    src3_reg_id = "RegId(VecRegClass, vmi.microVs2 + 1)"

    src1_ireg_id = "RegId(IntRegClass, _machInst.rs1)"
    src1_freg_id = "RegId(FloatRegClass, _machInst.rs1)"

    # The tail of vector mask inst should be treated as tail-agnostic.
    # We treat it with tail-undisturbed policy, since
    # the test suits only support undisturbed policy.
    num_src_regs = 0

    old_dest_reg_id = "RegId(VecRegClass, vmi.microVd)"
    set_src_reg_idx = ""
    if category in ["OPIVX", "OPMVX"]:
        set_src_reg_idx += setSrcWrapper(src1_ireg_id)
        num_src_regs += 1
    elif category in ["OPFVF"]:
        set_src_reg_idx += setSrcWrapper(src1_freg_id)
        num_src_regs += 1

    set_src_reg_idx += setSrcWrapper(src2_reg_id) # 1
    num_src_regs += 1
    set_src_reg_idx += setSrcWrapper(src3_reg_id) # 2
    num_src_regs += 1
    old_vd_idx = num_src_regs
    set_src_reg_idx += setOldDestWrapper(old_dest_reg_id)
    set_src_reg_idx += setSrcVL()
    set_src_reg_idx += setSrcVm()
    set_dest_reg_idx = setDestWrapper(dest_reg_id)
    vm_decl_rd = vmDeclAndReadData()
    microiop = InstObjParams(name + "_micro",
        Name + "Micro",
        microop_class_name,
        {'code': code,
         'set_dest_reg_idx': set_dest_reg_idx,
         'set_src_reg_idx': set_src_reg_idx,
         'vm_decl_rd': vm_decl_rd,
         'copy_old_vd': copyOldVd(old_vd_idx)},
        flags)
    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    # Because of the use of templates, we had to put all parts in header to
    # keep the compiler happy.
    header_output = \
        VectorSlideMicroDeclare.subst(microiop) + \
        VectorSlideMicroConstructor.subst(microiop) + \
        micro_execute_template.subst(microiop) + \
        VectorSlideMacroDeclare.subst(iop) + \
        macro_construtor.subst(iop)

    decode_block = decode_template.subst(iop)
    return (header_output, decode_block)

}};

def format VectorSlideUpFormat(code, category, *flags) {{
    (header_output, decode_block) = VectorSlideBase(name, Name, category, code,
        flags,
        macro_construtor = VectorSlideUpMacroConstructor,
        decode_template = VectorIntDecodeBlock,
        micro_execute_template = VectorSlideMicroExecute)
}};

def format VectorSlideDownFormat(code, category, *flags) {{
    (header_output, decode_block) = VectorSlideBase(name, Name, category, code,
        flags,
        macro_construtor = VectorSlideDownMacroConstructor,
        decode_template = VectorIntDecodeBlock,
        micro_execute_template = VectorSlideMicroExecute)
}};

def format VectorFloatSlideUpFormat(code, category, *flags) {{
    (header_output, decode_block) = VectorSlideBase(name, Name, category, code,
        flags,
        macro_construtor = VectorSlideUpMacroConstructor,
        decode_template = VectorFloatDecodeBlock,
        micro_execute_template = VectorFloatSlideMicroExecute)
}};

def format VectorFloatSlideDownFormat(code, category, *flags) {{
    (header_output, decode_block) = VectorSlideBase(name, Name, category, code,
        flags,
        macro_construtor = VectorSlideDownMacroConstructor,
        decode_template = VectorFloatDecodeBlock,
        micro_execute_template = VectorFloatSlideMicroExecute)
}};

def format VectorCompressFormat(code, category, *flags) {{
    iop = InstObjParams(name, Name, "VCompressMacroInst", flags)

    decode_block = VectorIntDecodeBlock.subst(iop)
}};
